﻿using System;
using System.IO;
using Common;

namespace Cache.FileCache
{
    /// <summary>
    /// 二进制文件缓存
    /// </summary>
    public class FileCache : ICache
    {
        public static object lockObj = new object();

        #region 构造函数

        public FileCache(string path)
        {
            CachePath = path;
        }

        #endregion

        #region 属性

        private int _cacheSubDirs = 1000;
        private bool _isCache = true;

        /// <summary>
        ///     文件路径
        /// </summary>
        public string CachePath { get; set; }

        /// <summary>
        ///     是否缓存
        /// </summary>
        public bool IsCache
        {
            set { _isCache = value; }
            get { return _isCache; }
        }

        /// <summary>
        ///     最大文件目录数,0为不分子目录
        /// </summary>
        public int CacheSubDirs
        {
            get { return _cacheSubDirs; }
            set { _cacheSubDirs = value; }
        }

        #endregion

        /// <summary>
        ///     设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public void Set(string key, object value)
        {
            Set(key, value, 0);
        }

        /// <summary>
        ///     设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <param name="extime"></param>
        /// <returns></returns>
        public void Set(string key, object value, int extime)
        {
            if (!IsCache)
                return;

            string filepath = GetFilePath(key);
            string xpath = DirectoryHelper.GetFilePath(filepath);

            lock (lockObj)
            {
                if (!DirectoryHelper.Exits(xpath))
                {
                    DirectoryHelper.CreateDirectory(xpath);
                }

                try
                {
                    var fmodel = new FileCacheModel {CreateTime = DateTime.Now, ExpirationTime = extime, Model = value};

                    SerializeHelper.SerializeToBinary(fmodel, filepath);
                }
                catch(Exception e)
                {
                    LogHelper.Logger.Error(e);
                }
            }
        }

        /// <summary>
        ///     获取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public object Get(string key)
        {
            if (!IsCache)
                return null;

            string filepath = GetFilePath(key);
            var f = new FileInfo(filepath);

            if (!f.Exists)
                return null;

            //string filepath = Path.Combine(BasePath, string.Format("{0}.xml", key));
            var fmodel = SerializeHelper.DeserializeFromBinary(typeof (FileCacheModel), filepath) as FileCacheModel;
            if (fmodel.ExpirationTime == 0)
            {
                return fmodel.Model;
            }

            TimeSpan ts = DateTime.Now - fmodel.CreateTime;
            if (ts.TotalSeconds >= fmodel.ExpirationTime)
            {
                Remove(key);
                return null;
            }

            return fmodel.Model;
        }

        public bool ContainsKey(string key)
        {
            if (!IsCache)
                return false;

            string filepath = GetFilePath(key);

            return File.Exists(filepath);
        }

        /// <summary>
        ///     删除缓存
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            if (!IsCache)
                return;

            string filepath = GetFilePath(key);

            lock (lockObj)
            {
                try
                {
                    var f = new FileInfo(filepath);
                    if (f.Exists)
                    {
                        f.Attributes = FileAttributes.Normal;
                        f.Delete();
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
        }

        /// <summary>
        ///     删除所有缓存
        /// </summary>
        public int RemoveAll()
        {
            if (!IsCache)
                return 0;

            string cachePath = DirectoryHelper.GetMapPath(CachePath);
            int result = Directory.GetFiles(cachePath).Length;
            lock (lockObj)
            {
                DirectoryHelper.DeleteDirectory(cachePath, false);
            }

            return result;
        }

        /// <summary>
        ///     获取缓存路径
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private string GetFilePath(string key)
        {
            //key = KeyPrefix + key;
            string filepath = "";

            //前缀
            //if (!string.IsNullOrEmpty(KeyPrefix))
            //{
            //    filepath += "\\" + KeyPrefix;
            //}

            // 绝对值取模
            if (CacheSubDirs != 0)
            {
                int n = Math.Abs(key.GetHashCode())%CacheSubDirs;
                filepath += "\\" + n.ToString();
            }

            //按"."分割key,以划分目录
            string[] strs = key.Split('.');
            for (int i = 0; i < strs.Length; i++)
            {
                filepath += "\\" + strs[i];
            }


            filepath = DirectoryHelper.GetMapPath(CachePath) + filepath + ".cache";
            return filepath;
        }
    }
}